package com.example.xd.model_video.clipvideo;

import android.animation.ValueAnimator;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.TextUtils;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import android.widget.VideoView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.example.xd.model_video.R;
import com.example.xd.model_video.videoeditlib.Constants;
import com.example.xd.model_video.videoeditlib.editVideoPlay.ExtractVideoInfoUtil;
import com.example.xd.model_video.videoeditlib.editVideoPlay.PictureUtils;
import com.zhy.adapter.recyclerview.CommonAdapter;
import com.zhy.adapter.recyclerview.base.ViewHolder;

import java.io.File;
import java.lang.ref.WeakReference;
import java.util.ArrayList;

import VideoHandle.EpEditor;
import VideoHandle.EpVideo;
import VideoHandle.OnEditorListener;

/**
 * @auther XuDan on 2019/7/17.
 */
public class ClipVideoUtil implements ClipVideoInterface {

    private static final String TAG = ClipVideoUtil.class.getSimpleName();


    private Context context;
    private ArrayList<VideoEditInfo> showLists = new ArrayList<>();
    private boolean isSeeking;
    private boolean isOverScaledTouchSlop;
    private VideoView videoView;
    private int lastScrollX;
    private int mScaledTouchSlop;
    private long scrollPos = 0;
    private float averageMsPx;//每毫秒所占的px;
    private ExtractVideoInfoUtil mExtractVideoInfoUtil;
    private int itemW;
    private int mMaxWidth;
    private String OutPutFileDirPath;
    private RecyclerView recyclerView;
    private RangeSeekBar seekBar;
    private long duration;
    private String video_path;
    private ImageView positionIcon;
    private static final String tempFileName = "clipTempFromVideo.mp4";
    private float averagePxMs;//每px所占用的ms毫秒
    private long leftProgress, rightProgress;


    private static final long MIN_CUT_DURATION = 3 * 1000L;// 最小剪辑时间3s
    private static final long MAX_CUT_DURATION = 30 * 1000L;//视频最多剪切多长时间
    private static final int MAX_COUNT_RANGE = 10;//seekBar的区域内一共有多少张图片
    private CommonAdapter<VideoEditInfo> mCommonAdapter;
    private ExtractFrameWorkThread mExtractFrameWorkThread;
    private Handler mUIHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == ExtractFrameWorkThread.MSG_SAVE_SUCCESS) {
                if (videoEditAdapter != null) {
                    VideoEditInfo info = (VideoEditInfo) msg.obj;
                    videoEditAdapter.addItemVideoInfo(info);
                    showLists.add(info);
                    mCommonAdapter.notifyDataSetChanged();
                }
            }
        }
    };
    private VideoEditAdapter videoEditAdapter;
    private ValueAnimator animator;
    private Handler handler = new Handler();


    private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                isSeeking = false;
            } else {
                isSeeking = true;
                if (isOverScaledTouchSlop && videoView != null && videoView.isPlaying()) {
                    onPause(videoView);
                }
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            isSeeking = false;
            int scrollX = getScrollXDistance();
            //达不到滑动的距离
            if (Math.abs(lastScrollX - scrollX) < mScaledTouchSlop) {
                isOverScaledTouchSlop = false;
                return;
            }
            isOverScaledTouchSlop = true;
            if (scrollX == -UIUtil.dip2px(context, 35)) {
                scrollPos = 0;
            } else {
                if (videoView != null && videoView.isPlaying()) {
                    onPause(videoView);
                }
                isSeeking = true;
                scrollPos = (long) (averageMsPx * (UIUtil.dip2px(context, 35) + scrollX));
                leftProgress = seekBar.getSelectedMinValue() + scrollPos;
                rightProgress = seekBar.getSelectedMaxValue() + scrollPos;
                videoView.seekTo((int) leftProgress);
            }
            lastScrollX = scrollX;
        }
    };

    public void onPause(VideoView videoView) {
        isSeeking = false;
        if (videoView != null && videoView.isPlaying()) {
            videoView.pause();
            handler.removeCallbacks(run);
        }
        if (positionIcon.getVisibility() == View.VISIBLE) {
            positionIcon.setVisibility(View.GONE);
        }
        positionIcon.clearAnimation();
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
    }


    private ClipVideoUtil() {
    }

    private static ClipVideoUtil instance = null;

    public static ClipVideoUtil getInstance() {
        if (instance == null) {
            synchronized (ClipVideoUtil.class) {
                instance = new ClipVideoUtil();
            }
        }
        return instance;
    }

    @Override
    public void initvideo(Context context, ClipView clipView, VideoView videoView, String video_path) {
        this.recyclerView = clipView.getRecycle();
        this.videoView = videoView;
        this.video_path = video_path;
        this.context = context;
        this.positionIcon = clipView.getPositionIcon();
        initPlay(videoView, video_path);
        init(clipView.getLl_seekBar());
    }

    private void initPlay(VideoView videoView, String video_path) {
        videoView.setVideoPath(video_path);
        videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
            @Override
            public void onPrepared(MediaPlayer mp) {
                videoView.start();
                videoStart();
                mp.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
                    @Override
                    public void onSeekComplete(MediaPlayer mp) {
                        if (!isSeeking) {
                            videoView.start();
                            videoStart();
                        }
                    }
                });
            }
        });
        videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
            @Override
            public void onCompletion(MediaPlayer mediaPlayer) {
                if (!isSeeking) {
                    videoView.start();
                    videoStart();
                }
            }
        });

    }


    @Override
    public void complexVideo(String video_path, ComplexListener listener) {
        if (rightProgress - leftProgress > 30000) {
            Toast.makeText(context, "超出30s", Toast.LENGTH_SHORT).show();
            return;
        }
        if (duration == rightProgress - leftProgress) {
            if (listener != null) {
                listener.noNeedComplex(video_path);
            }
            return;
        }
        if (!video_path.contains(".mp4") && !video_path.contains(".avi")) {
            Toast.makeText(context, "暂不支持该格式视频，请转码为MP4后再尝试", Toast.LENGTH_SHORT).show();
            return;
        }
        ArrayList<EpVideo> epVideos = new ArrayList<>();
        EpVideo epVideo = new EpVideo(video_path)
                .setVideoSourceSize(mExtractVideoInfoUtil.getVideoWidth(), mExtractVideoInfoUtil.getVideoHeight())
                .clip(leftProgress / 1000, (rightProgress - leftProgress) / 1000);
        epVideos.add(epVideo);
        File temp = new File(Constants.APPLICATION_VIDEO_PATH + tempFileName);
        if (temp.exists())
            temp.delete();
        int frameRate = mExtractVideoInfoUtil.getVideoFrameRate();
        EpEditor.OutputOption outputOption = new EpEditor.OutputOption(Constants.APPLICATION_VIDEO_PATH + tempFileName);
        outputOption.setWidth(1280);//输出视频宽，默认480
        outputOption.setHeight(720);//输出视频高度,默认360
        outputOption.frameRate = frameRate > 30 ? 30 : frameRate;//输出视频帧率,默认30
        outputOption.bitRate = 2000;//输出视频码率,默认10
        EpEditor.merge(epVideos, outputOption, new OnEditorListener() {
            @Override
            public void onSuccess() {
                if (listener != null) {
                    listener.complexSuccess(Constants.APPLICATION_VIDEO_PATH + tempFileName);
                }
            }

            @Override
            public void onFailure() {
                if (listener != null) {
                    listener.complexFail();
                }
            }

            @Override
            public void onProgress(float progress) {
                if (listener != null) {
                    listener.complexing(progress);
                }
            }
        });

    }

    private int getScrollXDistance() {
        LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
        int position = layoutManager.findFirstVisibleItemPosition();
        View firstVisibleChildView = layoutManager.findViewByPosition(position);
        int itemWidth = firstVisibleChildView.getWidth();
        return (position) * itemWidth - firstVisibleChildView.getLeft();
    }

    private void initRecycleView(RecyclerView recyclerView) {
        recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false));
        mCommonAdapter = new CommonAdapter<VideoEditInfo>(context, R.layout.video_item, showLists) {

            @Override
            protected void convert(ViewHolder viewHolder, VideoEditInfo videoEditInfo, int position) {
                String file = "file://";
                if (showLists.get(position) != null)
                    file += showLists.get(position).path;
                ImageView imageView = viewHolder.getView(R.id.id_image);
                Glide.with(context)
                        .load(file)
                        .diskCacheStrategy(DiskCacheStrategy.RESULT)
                        .into(imageView);
                ViewGroup.LayoutParams layoutParams = imageView.getLayoutParams();
                layoutParams.width = itemW;
            }
        };
        recyclerView.setAdapter(mCommonAdapter);
        recyclerView.addOnScrollListener(mOnScrollListener);
    }


    private void init(LinearLayout ll_seekbar) {
        initData();
        initRecycleView(recyclerView);

        long startPosition = 0;
        long endPosition = duration;
        int thumbnailsCount;
        int rangeWidth;
        boolean isOver_60_s;
        if (endPosition <= MAX_CUT_DURATION) {
            isOver_60_s = false;
            thumbnailsCount = MAX_COUNT_RANGE;
            rangeWidth = mMaxWidth;
        } else {
            isOver_60_s = true;
            thumbnailsCount = (int) (endPosition * 1.0f / (MAX_CUT_DURATION * 1.0f) * MAX_COUNT_RANGE);
            rangeWidth = mMaxWidth / MAX_COUNT_RANGE * thumbnailsCount;
        }
        recyclerView.addItemDecoration(new EditSpacingItemDecoration(UIUtil.dip2px(context, 35), thumbnailsCount));
        initSeekBar(ll_seekbar, endPosition, isOver_60_s);

        averageMsPx = duration * 1.0f / rangeWidth * 1.0f;
        OutPutFileDirPath = PictureUtils.getSaveEditThumbnailDir(context);
        int extractW = (UIUtil.getScreenWidth(context) - UIUtil.dip2px(context, 70)) / MAX_COUNT_RANGE;
        int extractH = UIUtil.dip2px(context, 55);
        MediaMetadataRetriever mMetadataRetriever = new MediaMetadataRetriever();
        mMetadataRetriever.setDataSource(context, Uri.parse(video_path));
        mExtractFrameWorkThread = new ExtractFrameWorkThread(context, extractW, extractH, mUIHandler, video_path, OutPutFileDirPath, startPosition, endPosition, thumbnailsCount);
        mExtractFrameWorkThread.start();
        leftProgress = 0;
        if (isOver_60_s) {
            rightProgress = MAX_CUT_DURATION;
        } else {
            rightProgress = endPosition;
        }
        averagePxMs = (mMaxWidth * 1.0f / (rightProgress - leftProgress));
    }

    private void initSeekBar(LinearLayout ll_seekbar, long endPosition, boolean isOver_60_s) {
        if (isOver_60_s) {
            seekBar = new RangeSeekBar(context, 0L, MAX_CUT_DURATION);
            seekBar.setSelectedMinValue(0L);
            seekBar.setSelectedMaxValue(MAX_CUT_DURATION);
        } else {
            seekBar = new RangeSeekBar(context, 0L, endPosition);
            seekBar.setSelectedMinValue(0L);
            seekBar.setSelectedMaxValue(endPosition);
        }
        seekBar.setMin_cut_time(MIN_CUT_DURATION);//设置最小裁剪时间
        seekBar.setNotifyWhileDragging(true);
        seekBar.setOnRangeSeekBarChangeListener(mOnRangeSeekBarChangeListener);
        ll_seekbar.addView(seekBar);
    }

    private void initData() {
        mExtractVideoInfoUtil = new ExtractVideoInfoUtil(video_path, context);
        duration = Long.valueOf(mExtractVideoInfoUtil.getVideoLength());
        mMaxWidth = UIUtil.getScreenWidth(context) - UIUtil.dip2px(context, 70);
        mScaledTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
        videoEditAdapter = new VideoEditAdapter(context,
                (UIUtil.getScreenWidth(context) - UIUtil.dip2px(context, 70)) / 10);
        itemW = (UIUtil.getScreenWidth(context) - UIUtil.dip2px(context, 70)) / 10;
    }

    @Override
    public void init(Context context) {

    }

    public void destory() {
        if (animator != null) {
            animator.cancel();
        }
        if (videoView != null) {
            videoView.stopPlayback();
        }
        if (mExtractVideoInfoUtil != null) {
            mExtractVideoInfoUtil.release();
        }
        recyclerView.removeOnScrollListener(mOnScrollListener);
        if (mExtractFrameWorkThread != null) {
            mExtractFrameWorkThread.stopExtract();
        }
        mUIHandler.removeCallbacksAndMessages(null);
        handler.removeCallbacksAndMessages(null);
        if (!TextUtils.isEmpty(OutPutFileDirPath)) {
            PictureUtils.deleteFile(new File(OutPutFileDirPath));
        }
    }


    public void onResume(VideoView videoView) {
        videoView.seekTo((int) leftProgress);
    }


    private Runnable run = new Runnable() {
        @Override
        public void run() {
            videoProgressUpdate();
            handler.postDelayed(run, 1000);
        }
    };

    private void videoProgressUpdate() {
        long currentPosition = videoView.getCurrentPosition();
        if (currentPosition >= (rightProgress)) {
            videoView.seekTo((int) leftProgress);
            positionIcon.clearAnimation();
            if (animator != null && animator.isRunning()) {
                animator.cancel();
            }
            anim();
        }
    }


    public void videoStart() {
        positionIcon.clearAnimation();
        if (animator != null && animator.isRunning()) {
            animator.cancel();
        }
        anim();
        handler.removeCallbacks(run);
        handler.post(run);
    }

    private void anim() {
        if (positionIcon.getVisibility() == View.GONE) {
            positionIcon.setVisibility(View.VISIBLE);
        }
        final FrameLayout.LayoutParams params = (FrameLayout.LayoutParams) positionIcon.getLayoutParams();
        int start = (int) (UIUtil.dip2px(context, 35) + (leftProgress/*mVideoView.getCurrentPosition()*/ - scrollPos) * averagePxMs);
        int end = (int) (UIUtil.dip2px(context, 35) + (rightProgress - scrollPos) * averagePxMs);
        animator = ValueAnimator
                .ofInt(start, end)
                .setDuration((rightProgress - scrollPos) - (leftProgress/*mVideoView.getCurrentPosition()*/ - scrollPos));
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                params.leftMargin = (int) animation.getAnimatedValue();
                positionIcon.setLayoutParams(params);
            }
        });
        animator.start();
    }

    private final RangeSeekBar.OnRangeSeekBarChangeListener mOnRangeSeekBarChangeListener = new RangeSeekBar.OnRangeSeekBarChangeListener() {
        @Override
        public void onRangeSeekBarValuesChanged(RangeSeekBar bar, long minValue, long maxValue, int action, boolean isMin, RangeSeekBar.Thumb pressedThumb) {
            Log.d(TAG, "-----minValue----->>>>>>" + minValue);
            Log.d(TAG, "-----maxValue----->>>>>>" + maxValue);
            leftProgress = minValue + scrollPos;
            rightProgress = maxValue + scrollPos;
            Log.d(TAG, "-----leftProgress----->>>>>>" + leftProgress);
            Log.d(TAG, "-----rightProgress----->>>>>>" + rightProgress);
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    Log.d(TAG, "-----ACTION_DOWN---->>>>>>");
                    isSeeking = false;
                    onPause(videoView);
                    break;
                case MotionEvent.ACTION_MOVE:
                    Log.d(TAG, "-----ACTION_MOVE---->>>>>>");
                    isSeeking = true;
                    videoView.seekTo((int) (pressedThumb == RangeSeekBar.Thumb.MIN ?
                            leftProgress : rightProgress));
                    break;
                case MotionEvent.ACTION_UP:
                    Log.d(TAG, "-----ACTION_UP--leftProgress--->>>>>>" + leftProgress);
                    isSeeking = false;
                    //从minValue开始播
                    videoView.seekTo((int) leftProgress);
                    break;
                default:
                    break;
            }
        }
    };
}
